use super::utils;
use anyhow::Result;
use serialport::{self, SerialPort};
use std::time::Duration;

const BAUDRATE: u32 = 115_200;
const _COMMAND_READ: &[u8] = &[0x01, 0x00, 0x00, 0xF0, 0x10, 0x00, 0x00, 0x00]; // 01 00 00 F0 10 00 00 00
const _COMMAND_INVENT: [u8; 8] = [0x01, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00];

#[derive(Clone, Default, Debug)]
pub struct Tag {
    pub epc: String,
    pub tid: String,
    pub rssi: u8,
}

pub struct DevR2K {
    pub port: Box<dyn SerialPort>,
}

#[derive(Clone, Debug, Default)]
pub struct R2KResult {
    pub r2ktype: String,
    pub content: Vec<u8>,
}

impl DevR2K {
    pub fn open(port_name: String) -> Result<Box<dyn SerialPort>> {
        let wait_time = Duration::from_millis(5);
        let port_build = serialport::new(port_name, BAUDRATE);
        let port: Box<dyn SerialPort> = port_build.timeout(wait_time).open()?;
        Ok(port)
    }

    pub fn init(port_name: String) -> Result<Self> {
        let result = DevR2K {
            port: DevR2K::open(port_name)?,
        };
        Ok(result)
    }

    pub async fn port_read(&mut self, read: &mut Vec<u8>, len: usize) -> Result<bool> {
        let mut result = false;
        if self.port.bytes_to_read()? > 0 {
            let mut temp: Vec<u8> = vec![0; len];
            let bytes_read = self.port.read(temp.as_mut_slice())?;
            temp.resize(bytes_read, 0);
            read.extend(temp);
            result = bytes_read == len;
        }
        Ok(result)
    }

    async fn pack_read(&mut self, read: &mut Vec<u8>, len: usize) -> Result<bool> {
        let mut result = self.port_read(read, len).await?;
        if read.len() < len && read.len() > 0 {
            tokio::time::sleep(Duration::from_millis(1)).await;
            let remain = len - read.len();
            result = self.port_read(read, remain).await?;
            println!("R2k CMD AutoPack:{:02X?}", read);
        }
        Ok(result)
    }

    pub async fn pars_await(&mut self, empty_limit: Option<usize>) -> Result<R2KResult> {
        let mut empty_count = 0;
        let mut result = R2KResult::default();
        loop {
            self.pack_read(&mut result.content, 8).await?;
            if !result.content.is_empty() {
                break;
            };
            empty_count += 1;
            if let Some(limit) = empty_limit {
                if empty_count > limit {
                    println!("out of time:{}", empty_count);
                    return Ok(result);
                }
            }
            tokio::time::sleep(Duration::from_millis(5)).await;
        }
        let (check_type, check_result) = match result.content.as_slice() {
            [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00] => {
                ("Begin", self.pack_read(&mut result.content, 8).await?)
            }
            [0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00] => {
                ("End", self.pack_read(&mut result.content, 8).await?)
            }
            [0x01, 0x12, 0x05, 0x00, _, 0x00, 0x00, 0x00] => {
                let len = 4 * (result.content[4] as usize);
                ("ReadEPC", self.pack_read(&mut result.content, len).await?)
            }
            [0x01, _, 0x06, 0x00, _, 0x00, 0x00, 0x00] => {
                //[0x01, 0x01, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00] //NOTID
                //[0x01, 0x80, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00]
                //[0x01, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00]
                let len = 4 * (result.content[4] as usize);
                ("ReadTID", self.pack_read(&mut result.content, len).await?)
            }
            _ => ("Unknow", self.pack_read(&mut result.content, 80).await?),
        };
        if check_result {
            result.r2ktype = check_type.to_string();
        }
        return Ok(result);
    }

    pub async fn pars_read(&mut self, data: &[u8], read_delay: u64) -> Result<Vec<R2KResult>> {
        self.port.write(data)?;
        tokio::time::sleep(Duration::from_millis(read_delay)).await;
        let mut pack_res: Vec<R2KResult> = Vec::new();
        loop {
            let r2k_res = self.pars_await(Some(100)).await?;
            pack_res.push(r2k_res.clone());
            match r2k_res.r2ktype.as_str() {
                "Begin" => {}
                "ReadEPC" => {}
                "ReadTID" => {}
                _ => break, // Error/Unknow/End 都直接退出
            }
            tokio::time::sleep(Duration::from_millis(5)).await
        }
        return Ok(pack_res);
    }

    pub fn to_raw_vec(pack_res: Vec<R2KResult>, ignore: bool) -> Vec<u8> {
        let mut result = Vec::new();
        let pac_array: Vec<&str> = pack_res.iter().map(|r2k| r2k.r2ktype.as_str()).collect();
        let pattern = match pac_array.as_slice() {
            ["Begin", .., "End"] => true,
            _ => false,
        };
        for res in pack_res {
            // EPC和TID各读两次
            match (res.r2ktype.as_str(), pattern, ignore) {
                ("ReadEPC", true, true) => {}
                ("ReadTID", true, true) => {}
                _ => result.extend(res.content),
            };
        }
        result
    }

    pub fn to_tag(pack_res: Vec<R2KResult>) -> Tag {
        let mut result = Tag::default();
        let pac_array: Vec<&str> = pack_res.iter().map(|r2k| r2k.r2ktype.as_str()).collect();
        match pac_array.as_slice() {
            ["Begin", .., "End"] => {
                // EPC和TID各读两次
                for res in pack_res {
                    match res.r2ktype.as_str() {
                        "ReadEPC" if res.content.len() > 22 => {
                            result.rssi = res.content[13] - res.content[12]; // 确保类型转换正确
                            result.epc = utils::hextostring(&res.content[22..]);
                            result.epc.truncate(24);
                            println!("ReadEPC:{:02X?}",result.epc)
                        }
                        "ReadTID" if res.content.len() > 20 => {
                            result.tid = utils::hextostring(&res.content[20..]);
                            println!("ReadTID:{:02X?}",result.tid)
                        }
                        _ => {}
                    }
                }
            }
            _ => {}
        };
        result
    }
}
